package com.handydata.antifraud.rule.action;

import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.bstek.urule.Utils;
import com.bstek.urule.model.flow.ActionNode;
import com.bstek.urule.model.flow.FlowAction;
import com.bstek.urule.model.flow.ins.FlowContext;
import com.bstek.urule.model.flow.ins.ProcessInstance;
import com.handydata.antifraud.bo.decisionexecrecord.DecisionExecRecordReqBO;
import com.handydata.antifraud.common.constant.AlarmInfoCode;
import com.handydata.antifraud.rule.RuleEngineVarCollector;
import com.handydata.antifraud.rule.funcs.Calculate;
import com.handydata.antifraud.service.AlarmInfoService;
import com.handydata.antifraud.service.DecisionExecRecordService;
import com.handydata.antifraud.to.RiskInputTO;
import com.handydata.antifraud.to.RiskMiddleTO;
import com.handydata.antifraud.to.RiskOutputTO;

/**
 * 规则计算Action类
 */
@Slf4j
@Component
public class RuleCalculateAction implements FlowAction {

    @Autowired
    private DecisionExecRecordService decisionExecRecordService;
    private static final ConcurrentHashMap<String, String> calculateMap = new ConcurrentHashMap<>();

    static {
        calculateMap.put("计算4个目标城市Gps距离", "calc4CityEachDistance");
        calculateMap.put("计算年龄", "calcAge");
        calculateMap.put("计算手机安装多种类型App的数量", "calcAppNums");
        calculateMap.put("计算城市级别", "calcCityLevel");
        calculateMap.put("计算公司名称是否包含中文", "calcCompanyContainsChinese");
        calculateMap.put("计算客户数", "calcCustomers");
//        calculateMap.put("计算家庭住址与Gps百度Gps距离", "calcHomeAddrBetweenGpsAndBdMap");
        calculateMap.put("计算Mac是否符合生成规则", "calcMacPattern");
        calculateMap.put("计算手机号归属地是否禁止区域", "calcPhoneAttributionForbiddenArea");
        calculateMap.put("计算加速度传感器合成加速度", "calcSensorAcce");
        calculateMap.put("计算单位名称相似度", "calcUnitNameSimilarity");
        calculateMap.put("计算反欺诈风险结果info3", "calcRiskOutputInfo3");
        calculateMap.put("计算反欺诈风险结果info4", "calcRiskOutputInfo4");
        calculateMap.put("计算手机分辨率", "calcXYDPI");
        calculateMap.put("计算有本和模型分数", "calcYouBenModelScore");
        calculateMap.put("计算TOPN城市", "calcCityInTopN");




    }
    @Autowired
    private AlarmInfoService alarmInfoService;
    @Override
    public void execute(ActionNode actionNode, FlowContext context, ProcessInstance processInstance) {
        String orderId =null;
        String caclcName1=null;
        try{
            long startTime=System.currentTimeMillis();
            RiskInputTO riskInputTO = RuleEngineVarCollector.collect(context, RiskInputTO.class).get();
            RiskMiddleTO riskMiddleTO = RuleEngineVarCollector.collect(context, RiskMiddleTO.class).get();
            RiskOutputTO riskOutputTO = RuleEngineVarCollector.collect(context, RiskOutputTO.class).get();
            orderId=riskInputTO.getOrderId();


            String calcName = calculateMap.get(actionNode.getName());
            caclcName1=calcName;
            //alarmInfoService.startWatchTimeOut(AlarmInfoCode.ALERT_ITEM_WS.getCode(),riskInputTO.getOrderId(),calcName);

            if(StringUtils.isNotEmpty(calcName)) {
                Calculate calculate = (Calculate)Utils.getApplicationContext().getBean(calcName);
                calculate.doCalc(riskInputTO, riskMiddleTO, riskOutputTO);

                CompletableFuture.runAsync(()->insertLog(calcName,startTime,riskInputTO,riskMiddleTO));

            } else {
                throw new RuntimeException(String.format("规则计算Action类名称:%s 不正确，请核对", actionNode.getName()));
            }
            log.info("规则计算Action{}耗时:{}",actionNode.getName(),(System.currentTimeMillis()-startTime));
        }catch (Exception ex){
            handleException(ex,actionNode,orderId,caclcName1);
        }
    }

    private void handleException(Exception e,ActionNode actionNode,String orderId,String beanName) {
        log.error("执行计算函数失败{} Error:{}",actionNode.getName(), e);
        alarmInfoService.sendWatchAbNormal(AlarmInfoCode.ALERT_ITEM_RULE.getCode(),
                orderId,beanName,AlarmInfoCode.ALARM_TYPE_ERR.getCode(),"执行计算函数出错",e);

    }
    private  void insertLog(String caclName,long startTime,RiskInputTO riskInputTO,RiskMiddleTO riskMiddleTO){
        DecisionExecRecordReqBO bo=new DecisionExecRecordReqBO();
        bo.setOrderId(riskInputTO.getOrderId());
        bo.setNodeName(caclName);
//        bo.setInput(JSON.toJSONString(riskInputTO));
        bo.setNodeType("2");//计算函数
        bo.setCreateTime(new Date(startTime));
//        bo.setOutput(JSON.toJSONString(riskMiddleTO));
        bo.setUpdateTime(new Date());
        bo.setElapsed(Long.valueOf(System.currentTimeMillis()-startTime).intValue());

        decisionExecRecordService.createDecisionExecRecord(bo);

    }

}
